/*
CTC协议从控端模块,游戏机使用此模块进行数据处理
根据https://gitee.com/GMSA/CTC文档定义
具体使用见CTCSlaveDemo.c文件
*/
#ifndef CTC_SLAVE_H
#define CTC_SLAVE_H
#include "CTCClient.h"

#define CTC_SLAVE_VERSION 1 // CTC从控端版本号
#define CTC_SLAVE_PRODUCTID 0 // 从控端产品ID,V1.0版本为0

/// @brief 初始化CTC从控端
/// @note 需要在程序初始化时调用,会初始化发送和接收缓冲区,并设置初始状态为尝试连接状态
/// @note 需要在主循环中每隔1ms调用CTC_Slave_Loop1ms()函数
/// @param  无
void CTC_Slave_Init(void);

/// @brief 主循环处理函数
/// @note 根据当前状态进行数据处理,发现发送缓冲区有数据就发送数据,发现接收缓冲区有数据就处理数据
/// @note 先判断缓冲区有要发送的数据就先发送,发送完成等待收到ACK后回调发送结果回调函数,如果发送超时未收到ACK就重发,重发超过最大次数就回调发送结果回调函数告知发送失败,如果连续9次都是超时将标记为断开连接,缓冲区的内容分两段先读取第一个字节为长度,然后就读取这个长度的数据调用CTC_Slave_SetSendDataCallback对应的函数发送出去,每次仅发送一条报文,并保证与上一次发送至少间隔CTC_MIN_FRAME_TIME毫秒.
/// @note 如果有接收但未处理的数据就处理接收数据,处理数据时从头读取缓冲区中有效数据并按协议帧进行解析,如果有完整的数据帧并校验通过就回应ACK并调用指令对应的回调函数,如果接收的数据是重复的就回应ACK但不调用回调函数,判断为重复数据是根据事务ID进行判断,如果事务ID与上次处理的相同就认为是重复数据,如果发现不符合协议格式或校验失败就忽略此数据,并发送ACK告诉对方具体错误.
/// @note 需要在主循环中每1ms调用一次
/// @param  无
void CTC_Slave_Loop1ms(void);

/// @brief 串口收到数据需要推送到此函数
/// @note 需要在串口接收中断中调用
/// @param data 接收到的数据指针
/// @param len 数据长度
void CTC_Slave_ReceiveData(uint8_t* data, uint16_t len);

/// @brief 设置当前状态
/// @param state 当前设备状态,0=无故障,非0=有故障,会将错误码上报给服务器
/// @param consumable 设备是否可消费1=不可消费,0=可消费
void CTC_Slave_SetSlaveState(uint16_t state, uint8_t consumable);

/// @brief 设置发送数据回调函数
/// @param callback 回调函数指针    
void CTC_Slave_SetSendDataCallback(CTC_SendDataCallback callback);

/// @brief 设置Master设备状态变化回调函数
/// @param callback 回调函数指针
void CTC_Slave_SetMasterStateChangeCallback(CTC_ConnStateChangeCallback callback);

/// @brief 设置数据发送结果回调函数
/// @param callback 回调函数指针
void CTC_Slave_SetDataSendResultCallback(CTC_MsgSendCallback callback);

/// @brief 获取Master端设备状态
/// @return 返回Master端设备状态,0=正常可用,1=等待配网,2=连接门店服务异常,3=网络无法连接,4=正在联网,未知状态返回CTC_STATE_UNKNOWN
uint8_t CTC_Slave_GetMasterDeviceState(void);

/// @brief 获取连接状态
/// @return 返回当前连接状态,参考CTC_ClientConnState
CTC_ClientConnState CTC_Slave_GetConnectState(void);

/// @brief 获取离线时间(秒)
/// @return 返回当前离线时间,单位秒,如果在线返回0
uint32_t CTC_Slave_GetOfflineTime(void);

/// @brief 获取重新连接次数
/// @return 返回当前重新连接次数
uint16_t CTC_Slave_GetReConnectTimes(void);

/// @brief 获取总接收字节数
/// @return 返回总接收字节数
uint32_t CTC_Slave_GetTotalReceivedBytes(void);

/// @brief 获取总发送字节数
/// @return 返回总发送字节数
uint32_t CTC_Slave_GetTotalSentBytes(void);

/// @brief 获取总接收正确消息数
/// @return 返回总接收正确消息数
uint32_t CTC_Slave_GetTotalReceivedMsgCount(void);

/// @brief 获取总发送正确消息数
/// @return 返回总发送正确消息数
uint32_t CTC_Slave_GetTotalSentMsgCount(void);

/// @brief 获取总接收错误消息数
/// @return 返回总接收错误消息数
uint32_t CTC_Slave_GetTotalReceivedErrorMsgCount(void);

/// @brief 获取当前连接的设备ID
/// @param deviceId 指向存储设备ID的指针,长度16字节
/// @return 0=已连接并且获取到了设备ID,其他值表示未连接或未获取到设备ID
uint8_t CTC_Slave_GetMasterDeviceId(uint8_t* deviceId);

/// @brief 设置Slave端的设备ID
/// @param deviceId 指向存储设备ID的指针,长度16字节
void CTC_Slave_SetDeviceId(const uint8_t* deviceId);

/// @brief 获取发送缓冲区数据长度
/// @return 返回发送缓冲区数据长度
uint16_t CTC_Slave_GetSendBufferDataLength(void);

/// @brief 获取发送缓冲区空闲长度
/// @return 返回发送缓冲区空闲长度
uint16_t CTC_Slave_GetSendBufferFreeLength(void);

/// @brief 获取接收缓冲区数据长度
/// @return 返回接收缓冲区数据长度
uint16_t CTC_Slave_GetReceiveBufferDataLength(void);

/// @brief 获取接收缓冲区空闲长度
/// @return 返回接收缓冲区空闲长度
uint16_t CTC_Slave_GetReceiveBufferFreeLength(void);

/// @brief 获取Master端支持的CTC协议版本
/// @return 返回Master端支持的CTC协议版本,如果未握手或未连接则返回0
uint16_t CTC_Slave_GetMasterCTCVersion(void);

/// @brief 打印过程的统计数据
void CTC_Slave_PrintStatistics(void);

///抄表业务指令的处理----------------------------------------------------------------

/// @brief 收到抄表请求指令回调函数指针类型
typedef void (*CTC_Slave_ReadMeterCallback)(void);

/// @brief 设置收到抄表请求指令回调函数
/// @param callback 回调函数指针
void CTC_Slave_SetReadMeterCallback(CTC_Slave_ReadMeterCallback callback);

/// @brief 发送抄表应答指令,码表类型和数量成对出现,码表类型为255表示无效数据,无效数据后面不能再放有效数据
/// @param msg 指向抄表结果消息结构体指针,如果没有有效数据可以传NULL,依次传入码表类型和数量,最多10对,不足10对后面补255代表结束
uint32_t CTC_Slave_SendMeterDataRsp(const CTC_MeterDataRspMsgV1* msg);

///投币业务指令的处理----------------------------------------------------------------
/// @brief 收到投币请求指令回调函数指针类型
/// @param msg 指向投币请求消息结构体指针
typedef void (*CTC_Slave_CoinInCallback)(const CTC_CoinInMsgV1* msg);

/// @brief 设置收到投币请求指令回调函数
/// @param callback 回调函数指针
void CTC_Slave_SetCoinInCallback(CTC_Slave_CoinInCallback callback);

/// @brief 发送投币应答指令
/// @param msg 指向投币应答消息结构体指针
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Slave_SendCoinInRsp(const CTC_CoinInRspMsgV1* msg);

//通道选择业务指令的处理----------------------------------------------------------------
/// @brief 收到通道选择指令回调函数指针类型
/// @param msg 指向通道选择消息结构体指针
typedef void (*CTC_Slave_ChannelSelCallback)(const CTC_ChannelSelMsgV1* msg);

/// @brief 设置收到通道选择指令回调函数
/// @param callback 回调函数指针
void CTC_Slave_SetChannelSelCallback(CTC_Slave_ChannelSelCallback callback);

//查询与设置单价业务指令的处理-----------------------------------------------------------
/// @brief 收到查询单价指令回调函数指针类型
typedef void (*CTC_Slave_QueryCoinPriceCallback)(void);
/// @brief 设置收到查询单价指令回调函数
/// @param callback 回调函数指针
void CTC_Slave_SetQueryCoinPriceCallback(CTC_Slave_QueryCoinPriceCallback callback);
/// @brief 发送查询单价应答指令
/// @param msg 指向查询单价消息结构体指针
/// @return 返回发送结果,0=没有成功加入发送队列,其他值代表发送的事务ID
uint32_t CTC_Slave_SendQueryCoinPriceRsp(const CTC_CoinPriceMsgV1* msg);

/// @brief 收到设置单价指令回调函数指针类型
typedef void (*CTC_Slave_SetCoinPriceCallback)(const CTC_CoinPriceMsgV1* msg);
/// @brief 设置收到设置单价指令回调函数
/// @param callback 回调函数指针
void CTC_Slave_SetSetCoinPriceCallback(CTC_Slave_SetCoinPriceCallback callback);

//氛围控制业务指令的处理----------------------------------------------------------------
/// @brief 发送氛围控制指令
/// @param msg 指向氛围控制消息结构体指针
uint32_t CTC_Slave_SendAtmosphereEvent(const CTC_AtmosphereDataV1* msg);

//游戏奖励业务指令的处理----------------------------------------------------------------
/// @brief 发送游戏奖励指令
/// @param msg 指向游戏奖励消息结构体指针
uint32_t CTC_Slave_SendGameReward(const CTC_RewardMsgV1* msg);

//实物奖励业务指令的处理----------------------------------------------------------------
/// @brief 发送实物奖励指令
/// @param msg 指向实物奖励消息结构体指针
uint32_t CTC_Slave_SendPhysicalReward(const CTC_PhysicalReportMsgV1* msg);

#endif // CTC_SLAVE_H

